#pragma once

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <unordered_map>
#include <fstream>

#include "Common.hpp"

using std::endl, std::cin, std::cout;
using std::string;
const std::string sep = "\r\n";
std::string blankLine = sep;
const std::string lineSep = " ";
const std::string headerSep = ":";
const std::string defaulthomepage = "./wwwroot";
const std::string http_version = "HTTP/1.0";
const string page404 = "./wwwroot/404.html";
const string firstPage = "index.html";
using namespace LogModule;
class httpRuest
{
private:
    std::string _req_line;
    std::vector<std::string> _req_header;
    std::string _blank_line;
    std::string _body;
    // 在反序列化的过程中，细化我们解析出来的字段
    std::string _method; // 提取方法
    std::string _uri;
    std::string _path;
    std::string _args;
    std::string _version;
    std::unordered_map<string, string> _headerKV;

    bool _isexec = false;

    void parseReqLine(std::string &req_line,
                      const std::string s)
    {
        std::stringstream ss(_req_line);
        // ?? 按照空格的分割形式重写在流的分割子串中
        ss >> _method >> _uri >> _version;
        // _uri = defaulthomepage + _uri;
    }

    bool splitString(const string &toSplitString, string &key, string &value, const string &sep)
    {
        auto pos = toSplitString.find(sep);
        if (pos == string::npos)
            return false;
        key = toSplitString.substr(0, pos);
        value = toSplitString.substr(pos + sep.size());
        return true;
    }

public:
    httpRuest()
    {
    }
    ~httpRuest()
    {
    }
    bool isHasArgs()
    {
        return _isexec;
    }
    void parseHeaderKV()
    {
        for (auto &header : _req_header)
        {
            std::string key, value;
            if (splitString(header, key, value, headerSep))
                _headerKV[key] = value;
        }
    }
    bool parseHeader(string &request_str)
    {
        string line;
        while (true)
        {
            auto r = ParseOneLine(request_str, &line, sep);
            if (r && !line.empty())
            {
                _req_header.push_back(line);
            }
            else if (r && line.empty())
            {
                _blank_line = sep;
                break;
            }
            else
                return false;
        }
        parseHeaderKV();
        return true;
    }
    void Deserialize(std::string &request_str)
    {

        if (ParseOneLine(request_str, &_req_line, sep))
        {
            // 提取请求行中的详细字段
            parseReqLine(_req_line, lineSep);
            parseHeader(request_str);
            _body = request_str;

            // 分析请求看其中是否会有参数
            if (_method == "POST")
            {
                _isexec = true; // 此时的参数就是在正文
                _args = _body;
                _path = _uri;
                LOG(LogLevel::DEBUG) << "_path: " << _path;
                LOG(LogLevel::DEBUG) << "_args: " << _args;
            }
            else if (_method == "GET")
            {
                auto pos = _uri.find("?");
                if (pos != string::npos)
                {
                    _isexec = true;
                    // * /login?name=zheng&passwd=131234 大部分的请求就会是这样的
                    _path = _uri.substr(0, pos);
                    _args = _uri.substr(pos + 1);
                    LOG(LogLevel::DEBUG) << "_path: " << _path;
                    LOG(LogLevel::DEBUG) << "_args: " << _args;
                }
            }
        }

        Print();
    }

    const string &Path() { return _path; }
    const string &Args() { return _args; }
    void Print()
    {
        cout << "_method: " << _method << endl;
        cout << "_uri: " << _uri << endl;
        cout << "_version: " << _version << endl;
        for (auto &[k, v] : _headerKV)
        {
            cout << k << "#" << v << endl;
        }

        cout << "_blank_line: " << _blank_line << endl;
        cout << "_body: " << _body << endl;
    }
    std::string Uri() const { return _uri; }
    void setUri(const string newUri)
    {
        _uri = newUri;
    }
    std::string getContent(const string path)
    {
        // // * 现在这样的还只是一个暂时的做法
        // string content;
        // std::ifstream in(_uri);
        // if (!in.is_open())
        //     return std::string();
        // string line;
        // while (std::getline(in, line))
        //     content += line;

        // in.close();
        // return content;
        // zdl:: 在使用上面的方法时，我们会发现，如果我们需要传输图片等信息的时候
        // zdl:: 按照字符流的方法就没有办法将图片读写清楚

        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
        {
            // 可选：抛出异常或记录错误（根据需求决定）
            return "";
        }

        // 获取文件大小（修正类型并检查有效性）
        in.seekg(0, std::ios::end);
        std::streamoff filesize = in.tellg(); // 使用正确的类型
        if (filesize < 0)
        { // 检查tellg()是否成功
            return "";
        }

        // 处理空文件（可选，也可直接resize(0)）
        if (filesize == 0)
        {
            return "";
        }

        // 调整string大小并读取内容（使用安全的缓冲区地址）
        std::string content;
        try
        {
            content.resize(static_cast<size_t>(filesize)); // 转换为size_t（字符串大小必须非负）
            in.seekg(0, std::ios::beg);
            in.read(&content[0], filesize); // 安全访问内部缓冲区
        }
        catch (const std::exception &e)
        {
            // 捕获resize或read抛出的异常（如内存不足）
            return "";
        }
        LOG(LogLevel::DEBUG) << content.size() << "\n";
        return content;
    }
    string surffix()
    {
        auto pos = _uri.rfind(".");
        if (pos == string::npos)
            return "";
        else
            return _uri.substr(pos);
    }
};

// zdl:: 任何http请求都要有应答
class httpResponse
{
private:
    std::string _resq_line;
    std::vector<std::string> _resp_header;
    std::string _blank_line;
    std::string _body;
    // 必要的元素
    string _version;
    int _status_code;
    string _status_desc;
    string _content;
    std::unordered_map<string, string> _headerKV;

public:
    httpResponse() : _version(http_version), _blank_line(sep)
    {
    }
    ~httpResponse()
    {
    }
    void setCode(int code)
    {
        _status_code = code;
        _status_desc = code2Desc(_status_code);
    }
    void setBody(const string &body)
    {
        _body = body;
    }

    void setHeader(const string &k, const string &v)
    {
        _headerKV[k] = v;
        
    }
    void Bulid(httpRuest &req)
    {
// #define testRedir 0
#ifdef testRedir
        _status_code = 302;
        _status_desc = code2Desc(_status_code); // 这个和状态码是强相关的
        setHeader("Location", "http://www.qq.com");
        for (auto &header : _headerKV)
        {
            _resq_header.emplace_back(
                header.first + headerSep + header.second + headerSep);
        }
#else
        // testRedir
        string Uri = defaulthomepage + req.Uri();
        if (Uri.back() == '/')
        {
            Uri += firstPage;
            req.setUri(Uri);
        }
        _content = req.getContent(Uri);
        LOG(LogLevel::INFO) << "---------客户端正在请求" << req.Uri();
        req.Print();

        LOG(LogLevel::DEBUG) << "----------------";
        if (_content.empty())
        {
            // 此时用户的请求不存在
            LOG(LogLevel::DEBUG) << "资源申请失败" << "\n";
            _status_code = 404;
            req.setUri(page404);
            _content = req.getContent(page404);
        }
        else
        {
            _status_code = 202;
        }
        _status_desc = code2Desc(_status_code);
        if (!_content.empty())
        {
            setHeader("Content-Length", std::to_string(_content.size()));
        }
        string mime_type = suffix2Desc(req.surffix());
        setHeader("Content-Type", mime_type);
        _body = _content;


#endif
    }

    void serialize(string *resq_str)
    {
        for (auto& [x, y] : _headerKV)
        {
            _resp_header.emplace_back(
                x + headerSep + y
            );
        }
        _resq_line = _version + lineSep +
                     std::to_string(_status_code) + lineSep +
                     _status_desc + sep;
        // 序列化
        *resq_str = _resq_line;

        for (auto &line : _resp_header)
        {
            *resq_str += (line + sep);
        }

        *resq_str += _blank_line;
        *resq_str += _body;
    }

private:
    const string code2Desc(int &code)
    {
        switch (code)
        {
        case 202:
            return "OK";
        case 404:
            return "Not Found";
        case 301:
            return "";
        case 302:
            return "";
        default:
            return "Unkonwn Request";
            break;
        }
    }
    const string suffix2Desc(const string &suffix)
    {
        if (suffix == ".html")
            return "text/html";
        // else if (suffix == ".png")
        // return "image/png";
        else
            return "text/html";
    }
};